#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/1/11 12:08
# @Author : 闫峰
# @File    : execute_strategy.py
import datetime
import decimal
import json
from decimal import Decimal

import requests

from common.setting import ensure_path_sep
from utils.mysqlUtils.db_pool import Database
import os
import threading
import time
from common.setting import ensure_path_sep
from utils.logging_tool.log_control import LogHandler
from utils.mysqlUtils.db_pool import Database
from utils.mysqlUtils.mongodb_utils import MongoDBLink

current_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_path)
path_list = current_path.split("\\")
dis_path = "\\".join(path_list[-2:-1])


def remove_file(info_path):
    if os.path.exists(info_path):
        os.remove(info_path)
    else:
        print(f"{info_path} 不存在")


info_path = ensure_path_sep(f"\\logs\\info-{dis_path}{time.time()}")
error_path = ensure_path_sep(f"\\logs\\\error-{dis_path}{time.time()}.log")
warning_path = ensure_path_sep(f"\\logs\\warning-{dis_path}{time.time()}.log")
remove_file(info_path)
remove_file(error_path)
remove_file(warning_path)
INFO = LogHandler(info_path, level='info')
ERROR = LogHandler(error_path, level='error')
WARNING = LogHandler(warning_path, level='warning')
class ExecuteStrategy:
    db = Database(ensure_path_sep("\\config\\shopeev2_config.yaml.bak"), "test_jdw_database")
    # 定义mongodb
    modb = MongoDBLink(
        uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
        dbname='test_zhcxkj_java_center', coll_name='t_sku_strategy_relation')

    def __init__(self,strategy_id,source_id):
        get_t_allegro_marketing_strategy = """
        			 SELECT status,sku_template_id,listing_template_id,strategy_type,price_template_id
			 FROM test_zhcxkj_center_strategy_comprehensive.t_allegro_marketing_strategy a
			WHERE a.id = %s
        """
        get_t_allegro_price_filter_template = """
                			 SELECT 
                			 price_adjust_plan,
                			 calculator_formula_id,
                			 price_percentage,
                			 price_adjust_type,
                			 min_price,
                			 max_price,
                			 min_profit,
                			 max_profit,
                			 status,
                			 sell_price_type
        			 FROM test_zhcxkj_center_strategy_comprehensive.t_allegro_price_filter_template a
        			WHERE a.id = %s
                """
        t_allegro_marketing_strategy = self.db.fetch_all_tuple(get_t_allegro_marketing_strategy,(strategy_id,))
        status = t_allegro_marketing_strategy[0][0]
        if status == 0:
            raise Exception("策略状态是禁用")
        self.strategy_id= strategy_id
        self.source_id = source_id
        self.sku_template_id = t_allegro_marketing_strategy[0][1]
        self.listing_template_id = t_allegro_marketing_strategy[0][2]
        self.strategy_type = t_allegro_marketing_strategy[0][3]
        self.price_template_id = t_allegro_marketing_strategy[0][4]
        self.num = source_id % 8 + 1
        t_allegro_price_filter_template = self.db.fetch_all_tuple(get_t_allegro_price_filter_template,(self.price_template_id,))
        if len(t_allegro_price_filter_template):
            self.price_adjust_plan = t_allegro_price_filter_template[0][0]
            self.calculator_formula_id = t_allegro_price_filter_template[0][1]
            self.price_percentage = t_allegro_price_filter_template[0][2]
            self.price_adjust_type = t_allegro_price_filter_template[0][3]
            self.min_price = t_allegro_price_filter_template[0][4]
            self.max_price = t_allegro_price_filter_template[0][5]
            self.min_profit = t_allegro_price_filter_template[0][6]
            self.max_profit = t_allegro_price_filter_template[0][7]
            self.allegro_price_filter_template_status = t_allegro_price_filter_template[0][8]
            self.sell_price_type = t_allegro_price_filter_template[0][9]
            if not self.allegro_price_filter_template_status:
                raise Exception("调价模板状态未开启")

    def execute_strategy(self):
        t_allegro_listing_template_detail = f"t_allegro_listing_template_detail_{self.listing_template_id}"
        self.t_allegro_listing_template_detail = MongoDBLink(
            uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
            dbname='test_zhcxkj_java_center', coll_name=t_allegro_listing_template_detail)

        expect_offer_id_set = set()
        #获取最小的ObjectId
        filters_ObjectId_min = {
            "$and": [
                {"listingTemplateId": self.listing_template_id},
                {"sourceId": self.source_id}
            ]
        }
        projection1 = {"_id": 1,"offerId": 1}
        res_id_index = self.t_allegro_listing_template_detail.select_skip_projection_limit(filters_ObjectId_min,projection1, "_id", 1)
        if not res_id_index:
            return
        first_data = res_id_index
        _id_index=res_id_index[0]['_id']
        while True:
            filters_ObjectId = {
                "$and": [
                    {"listingTemplateId": self.listing_template_id},
                    {"sourceId": self.source_id},
                    {"_id" :{"$gt":_id_index}}
                ]
            }
        # filter_sql = {"listingTemplateId": listing_template_id, "sourceId":source_id,"_id": {"$gte": _id_index }}

            field_ = {"offerId": 1, "_id": 1,"sku":1}


            actual_offer_id_list = self.t_allegro_listing_template_detail.select_skip_projection_limit(filters_ObjectId,field_,"_id",100)
            if first_data:
                actual_offer_id_list += first_data
                first_data.clear()
            if not len(actual_offer_id_list):
                break
            _id_index = actual_offer_id_list[-1].get('_id')
            if not self.sku_template_id:
                current_offer_id_set = set(map(lambda x: x['offerId'], actual_offer_id_list))
                # 过滤 调价模板
                if self.price_template_id:
                    current_offer_id_filter_adjuct_price_model_set = self.filter_adjust_model(current_offer_id_set)
                    expect_offer_id_set |= current_offer_id_filter_adjuct_price_model_set
            elif self.sku_template_id:
                # 匹配sku分级策略
                filter_sql = {"strategy_relation.strategy_id": self.strategy_id}
                field_ = {"sku":1, "_id": 0}
                get_stragety_sku_list = self.modb.select(filter_sql,field_)
                stragety_sku_list = list(map(lambda x:x['sku'],get_stragety_sku_list))
                expect_offer_id_set = set(filter(lambda x:x[2] in stragety_sku_list,actual_offer_id_list))
        # 得到一个actual_offer_id_set
        self.check_actual_offer_id_set(expect_offer_id_set)


    def init_strategy(self,strategy_id,source_id):
        get_t_allegro_marketing_strategy = """
                			 SELECT status,sku_template_id,listing_template_id,strategy_type
        			 FROM test_zhcxkj_center_strategy_comprehensive.t_allegro_marketing_strategy a
        			WHERE a.id = %s
                """
        t_allegro_marketing_strategy = self.db.fetch_all_tuple(get_t_allegro_marketing_strategy, (strategy_id,))
        status = t_allegro_marketing_strategy[0][0]
        if status == 0:
            raise Exception("策略状态是禁用")
        strategy_id = strategy_id
        source_id = source_id
        sku_template_id = t_allegro_marketing_strategy[0][1]
        listing_template_id = t_allegro_marketing_strategy[0][2]
        strategy_type = t_allegro_marketing_strategy[0][3]
        return source_id,sku_template_id,listing_template_id,strategy_type

    def check_actual_offer_id_set(self, expect_offer_id_set):
        t_allegro_listing_template_detail = MongoDBLink(
            uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
            dbname='test_zhcxkj_java_center', coll_name="t_allegro_strategy_adjust_price_detail")
        filter_sql = {"sourceId":self.source_id,"strategyId":self.strategy_id}
        field_ = {"offerId": 1}
        res = t_allegro_listing_template_detail.select(filter_sql,field_)
        actual_offer_id_set = set(map(lambda x:x['offerId'],res))
        if expect_offer_id_set != actual_offer_id_set:
            print()


    def getCalculationGrossProfitMarginViewModelList(self,calculationFormulaId,orderSourceId,listing_id_list):
        request_json = {
            "input": [

            ]
        }
        for lising in listing_id_list:
            sku_model = {
                "businessTypeCode": "AllegroLocalWarehouse",
                "calculationFormulaId": calculationFormulaId,
                "country": "PL",
                "customerId": 1,
                "orderSourceId": orderSourceId,
                "platformId": 67,
                "price": str(lising[2]),
                "sku": lising[3],
                "warehouseId": 5312,
                "warehouseTypeId": 1
            }
            request_json['input'].append(sku_model)
        request_headers = {
           "Authorization":"Basic aXJvYm90Ym94OmkxcjVvOEJvdGJveA=="
        }
        res = requests.post(url="http://calculatorapi.internal.zhcxkj.com/api/CalculationFormula/CalculationPrice/GetCalculatorPriceViewModelList",
                            headers=request_headers,
                            json=request_json)
        sku_GrossProfitMargin_map = {}
        for data in res.json()['data']:
            sku_GrossProfitMargin_map[data["Sku"]+"@" + '{:.2f}'.format(data["Price"])] = str(data['GrossProfitMargin'])
        return sku_GrossProfitMargin_map

    def get_price(self,calculationFormulaId,orderSourceId,sku):
        request_json = {
            "input": {
                "businessTypeCode": "AllegroLocalWarehouse",
                "country": "PL",
                "PlatformId": 67,
                "customerId": 1,
                "orderSourceId": orderSourceId,
                "platformId": 1,
                "skuList": [
                    sku
                ],
                "warehouseId": 5312,
                "warehouseTypeId": 1,
                "CalculationFormulaId": calculationFormulaId
            }
        }
        request_headers = {
           "Authorization":"Basic aXJvYm90Ym94OmkxcjVvOEJvdGJveA=="
        }
        res = requests.post(url="http://calculatorapi.internal.zhcxkj.com/api/CalculationFormula/CalculationPrice/GetCalculatorPriceViewModelList",
                            headers=request_headers,
                            json=request_json)
        if res.status_code == 200:
            return Decimal(str(res.json()['data'][0]['Price']))


    def filter_adjust_model(self,current_offer_id_set):
        # 还原

        get_data_set = f"""
                SELECT offer_id,price,sku
        FROM `test_zhcxkj_center_listing_comprehensive`.`t_allegro_listing_{self.num}` 
        WHERE offer_id in %s
        """
        listing_id_list = self.db.fetch_all_tuple(get_data_set, (current_offer_id_set,))
        filter_listing_id_list = None
        # 最终售价
        if self.price_adjust_plan == 1:
            filter_listing_id_list = self.handlerFinalsellingprice(listing_id_list)
        # 计算器公式
        elif self.price_adjust_plan == 2:
            filter_listing_id_list = self.handlerCalculatorFormulas(listing_id_list)

        return set(map(lambda x:x[0],filter_listing_id_list))


    def handlerFinalsellingprice(self,listing_id_list):
        """
        调价方案： 最终售价
        根据最终售价算法，得到调整后的价格
        1 如果类型是价格区间
            验证 调整后的价格 在  原始价格*self.min_price ——  原始价格*self.max_price之间
        2 如果是利润区间
            调研计算器得到每一条数据的利润率  验证利润率 是否在 self.min_profit—— self.max_profit 之间
        :param listing_id_list:
        :return:
        """
        filter_listing_id_list = None
        listing_id_list_map = None
        # 将 listing_id_list -> offer_id,price,adjust_price,sku
        if self.sell_price_type == 1:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] * (100 - self.price_percentage) / 100, x[2]),
                    listing_id_list))
        elif self.sell_price_type == 2:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] * (100 + self.price_percentage) / 100, x[2]),
                    listing_id_list))
        elif self.sell_price_type == 3:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] - self.price_percentage, x[2]), listing_id_list))
        elif self.sell_price_type == 4:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] + self.price_percentage, x[2]), listing_id_list))
        # offer_id,price,adjust_price,sku  ->  adjust_price 变成2位小数
        listing_id_list_map = list(
            map(lambda x: (x[0], x[1], x[2].quantize(decimal.Decimal('0.01')), x[3]), listing_id_list_map))
        # 价格区间
        if self.price_adjust_type == 1:
            # 过滤数据
            filter_listing_id_list = list(
                filter(lambda x: (x[1] * self.min_price / 100) <= x[2] <= (x[1] * self.max_price / 100),
                       listing_id_list_map))
        # 利润区间
        elif self.price_adjust_type == 2:
            sku_GrossProfitMargin_map = self.getCalculationGrossProfitMarginViewModelList(
                self.calculator_formula_id, self.source_id, listing_id_list_map)
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[2], sku_GrossProfitMargin_map.get(x[3] + "@" + '{:.2f}'.format(x[2])),x[3]),
                    listing_id_list_map))
            # 过滤掉利润率负数
            def negative(listing_id_list_map):
                a = listing_id_list_map[3]
                return not float(a) < 0.00
            filter_listing_id_list = list(filter(negative, listing_id_list_map))
            filter_listing_id_list = list(
                filter(lambda x: self.min_profit <= Decimal(x[3]) <= self.max_profit,
                       filter_listing_id_list))
        return filter_listing_id_list


    def handlerCalculatorFormulas(self,listing_id_list):
        """
        调价方案： 计算器公式
        根据计算器公式，得到调整后的价格  验证是否在  原始价格*self.min_price ——  原始价格*self.max_price之间
        :param listing_id_list:
        :return:
        """
        # map数据
        listing_id_list_map = list(
            map(lambda x: (x[0], x[1], self.get_price(self.calculator_formula_id,self.source_id,x[2]), x[2]),
                listing_id_list))
        # 过滤数据
        filter_listing_id_list = list(
            filter(lambda x: (x[1] * self.min_price / 100) <= x[2] <= (x[1] * self.max_price / 100),
                   listing_id_list_map))
        return filter_listing_id_list

if __name__ == '__main__':
    # 9046
    # 9058
    # 9059
    # 9062


    ExecuteStrategy(218,9046).execute_strategy()
    # ExecuteStrategy(1,9058).check_actual_offer_id_set()
